'use client' import { useState } from 'react' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Badge } from '@/components/ui/badge' import { Separator } from '@/components/ui/separator' import { Alert, AlertDescription } from '@/components/ui/alert' import { Loader2, Play, CheckCircle, XCircle, Send, Plus, Minus } from 'lucide-react' import { toast } from 'sonner' // SOAP 송신 함수들 import import { confirmTestPCR, confirmPCR } from '@/lib/soap/ecc/send/pcr-confirm' import { cancelTestRFQ, cancelRFQ } from '@/lib/soap/ecc/send/cancel-rfq' import { sendTestRFQInformation, sendRFQInformation } from '@/lib/soap/ecc/send/rfq-info' import { createTestPurchaseOrder, createPurchaseOrder } from '@/lib/soap/ecc/send/create-po' interface TestResult { success: boolean message: string responseData?: string timestamp: string duration?: number statusCode?: number endpoint?: string headers?: Record requestXml?: string requestHeaders?: Record } export default function ECCSenderTestPage() { const [isLoading, setIsLoading] = useState<{ [key: string]: boolean }>({}) const [testResults, setTestResults] = useState<{ [key: string]: TestResult }>({}) // 테스트 실행 공통 함수 // eslint-disable-next-line @typescript-eslint/no-explicit-any const runTest = async (testName: string, testFunction: () => Promise) => { setIsLoading(prev => ({ ...prev, [testName]: true })) const startTime = Date.now() try { const result = await testFunction() const duration = Date.now() - startTime const testResult: TestResult = { success: result.success, message: result.message, responseData: result.responseData, timestamp: new Date().toLocaleString('ko-KR'), duration, statusCode: result.statusCode, endpoint: result.endpoint, headers: result.headers, requestXml: result.requestXml, requestHeaders: result.requestHeaders } setTestResults(prev => ({ ...prev, [testName]: testResult })) if (result.success) { toast.success(`${testName} 테스트 성공`) } else { toast.error(`${testName} 테스트 실패: ${result.message}`) } } catch (error) { const testResult: TestResult = { success: false, message: error instanceof Error ? error.message : '알 수 없는 오류', timestamp: new Date().toLocaleString('ko-KR'), duration: Date.now() - startTime } setTestResults(prev => ({ ...prev, [testName]: testResult })) toast.error(`${testName} 테스트 오류: ${testResult.message}`) } finally { setIsLoading(prev => ({ ...prev, [testName]: false })) } } // PCR 확인 테스트 const [pcrData, setPcrData] = useState({ PCR_REQ: 'TEST_PCR01', PCR_REQ_SEQ: '00001', PCR_DEC_DATE: '20241201', EBELN: 'TEST_PO01', EBELP: '00010', PCR_STATUS: 'A', WAERS: 'KRW', PCR_NETPR: '1000.00', PEINH: '1', PCR_NETWR: '1000.00', CONFIRM_CD: 'CONF', CONFIRM_RSN: '테스트 확인' }) // RFQ 취소 테스트 const [rfqCancelData, setRfqCancelData] = useState({ ANFNR: 'TEST_RFQ_001' }) // RFQ 정보 전송 테스트 const [rfqInfoData, setRfqInfoData] = useState({ // 헤더 정보 ANFNR: 'RFQ0000001', LIFNR: '1000000001', WAERS: 'KRW', ZTERM: '0001', INCO1: 'FOB', INCO2: 'Seoul, Korea', MWSKZ: 'V0', LANDS: 'KR', VSTEL: '001', LSTEL: '001', // 아이템 정보 ANFPS: '00001', NETPR: '1000.00', NETWR: '1000.00', BRTWR: '1100.00', LFDAT: '20241201' }) // PO 생성 테스트 const [poData, setPoData] = useState({ header: { ANFNR: 'TEST001', LIFNR: '1000000001', ZPROC_IND: 'A', ANGNR: 'TEST001', WAERS: 'KRW', ZTERM: '0001', INCO1: 'FOB', INCO2: 'Seoul, Korea', MWSKZ: 'V0', LANDS: 'KR', ZRCV_DT: '20241201', ZATTEN_IND: 'Y', IHRAN: '20241201', TEXT: 'Test PO Creation', LSTEL: '', VSTEL: '', ZDLV_CNTLR: '', ZDLV_PRICE_NOTE: '', ZDLV_PRICE_T: '' }, items: [{ ANFNR: 'TEST001', ANFPS: '00001', LIFNR: '1000000001', NETPR: '1000.00', PEINH: '1', BPRME: 'EA', NETWR: '1000.00', BRTWR: '1100.00', LFDAT: '20241201', EBELP: '', ZCON_NO_PO: '' }], prReturn: [{ ANFNR: 'TEST001', ANFPS: '00001', EBELN: 'PR001', EBELP: '00001', MSGTY: 'S', MSGTXT: 'Test message' }] }) // PO 아이템 관리 함수들 const addPoItem = () => { const newItemIndex = poData.items.length + 1 setPoData(prev => ({ ...prev, items: [...prev.items, { ANFNR: prev.header.ANFNR, ANFPS: String(newItemIndex).padStart(5, '0'), LIFNR: prev.header.LIFNR, NETPR: '0.00', PEINH: '1', BPRME: 'EA', NETWR: '0.00', BRTWR: '0.00', LFDAT: prev.header.IHRAN, EBELP: '', ZCON_NO_PO: '' }] })) } const removePoItem = (index: number) => { if (poData.items.length > 1) { setPoData(prev => ({ ...prev, items: prev.items.filter((_, i) => i !== index) })) } } const updatePoItem = (index: number, field: string, value: string) => { setPoData(prev => ({ ...prev, items: prev.items.map((item, i) => i === index ? { ...item, [field]: value } : item ) })) } const updatePoHeader = (field: string, value: string) => { setPoData(prev => ({ ...prev, header: { ...prev.header, [field]: value } })) } return (

ECC SOAP Sender 테스트

4개의 ECC SOAP 송신 라이브러리를 테스트합니다

개발/테스트 환경
PCR 확인 RFQ 취소 RFQ 정보 PO 생성 {/* PCR 확인 탭 */} PCR (Price Change Request) 확인 PCR 확인 요청을 ECC로 전송합니다. (IF_ECC_EVCP_PCR_CONFIRM)
setPcrData(prev => ({ ...prev, PCR_REQ: e.target.value }))} placeholder="PCR 요청번호 (최대 10자)" />
setPcrData(prev => ({ ...prev, PCR_REQ_SEQ: e.target.value }))} placeholder="PCR 요청순번 (5자리 숫자)" />
setPcrData(prev => ({ ...prev, PCR_DEC_DATE: e.target.value }))} placeholder="YYYYMMDD 형식" />
setPcrData(prev => ({ ...prev, EBELN: e.target.value }))} placeholder="구매오더 번호" />
setPcrData(prev => ({ ...prev, EBELP: e.target.value }))} placeholder="구매오더 품번" />
setPcrData(prev => ({ ...prev, PCR_STATUS: e.target.value }))} placeholder="PCR 상태 (1자)" />
{/* 테스트 결과 표시 */} {(testResults['PCR 확인 (샘플)'] || testResults['PCR 확인 (사용자)']) && (

테스트 결과

{testResults['PCR 확인 (샘플)'] && ( )} {testResults['PCR 확인 (사용자)'] && ( )}
)}
{/* RFQ 취소 탭 */} RFQ (Request for Quotation) 취소 RFQ 취소 요청을 ECC로 전송합니다. (IF_ECC_EVCP_CANCEL_RFQ)
setRfqCancelData(prev => ({ ...prev, ANFNR: e.target.value }))} placeholder="RFQ 번호 (최대 10자)" />
{/* 테스트 결과 표시 */} {(testResults['RFQ 취소 (샘플)'] || testResults['RFQ 취소 (사용자)']) && (

테스트 결과

{testResults['RFQ 취소 (샘플)'] && ( )} {testResults['RFQ 취소 (사용자)'] && ( )}
)}
{/* RFQ 정보 탭 */} RFQ 정보 전송 RFQ 정보를 ECC로 전송합니다. (IF_EVCP_ECC_RFQ_INFORMATION)

RFQ 헤더 정보

setRfqInfoData(prev => ({ ...prev, ANFNR: e.target.value }))} placeholder="RFQ 번호" />
setRfqInfoData(prev => ({ ...prev, LIFNR: e.target.value }))} placeholder="공급업체 계정번호" />
setRfqInfoData(prev => ({ ...prev, WAERS: e.target.value }))} placeholder="통화 코드 (예: KRW)" />
setRfqInfoData(prev => ({ ...prev, ZTERM: e.target.value }))} placeholder="지불조건 키" />

RFQ 아이템 정보

setRfqInfoData(prev => ({ ...prev, ANFPS: e.target.value }))} placeholder="RFQ 아이템 번호" />
setRfqInfoData(prev => ({ ...prev, NETPR: e.target.value }))} placeholder="순가격" />
setRfqInfoData(prev => ({ ...prev, NETWR: e.target.value }))} placeholder="순주문가격" />
setRfqInfoData(prev => ({ ...prev, BRTWR: e.target.value }))} placeholder="총주문가격" />
{/* 테스트 결과 표시 */} {(testResults['RFQ 정보 (샘플)'] || testResults['RFQ 정보 (사용자)']) && (

테스트 결과

{testResults['RFQ 정보 (샘플)'] && ( )} {testResults['RFQ 정보 (사용자)'] && ( )}
)}
{/* PO 생성 탭 */} PO (Purchase Order) 생성 구매주문 생성 요청을 ECC로 전송합니다. (IF_ECC_EVCP_PO_CREATE) - 하나의 PO에 여러 PR 아이템들을 포함시키는 구조 {/* PO 헤더 정보 */}

PO 헤더 정보

{poData.items.length}개 아이템
updatePoHeader('ANFNR', e.target.value)} placeholder="입찰번호 (ANFNR)" />
updatePoHeader('LIFNR', e.target.value)} placeholder="공급업체 계정 (LIFNR) : 벤더코드" />
updatePoHeader('ZPROC_IND', e.target.value)} placeholder="처리상태 (ZPROC_IND)" />
updatePoHeader('ANGNR', e.target.value)} placeholder="협상번호 (ANGNR)" />
updatePoHeader('WAERS', e.target.value)} placeholder="통화 (WAERS)" />
updatePoHeader('ZTERM', e.target.value)} placeholder="지급조건 (ZTERM)" />
updatePoHeader('INCO1', e.target.value)} placeholder="인코텀즈1 (INCO1)" />
updatePoHeader('INCO2', e.target.value)} placeholder="인코텀즈2 (INCO2)" />
updatePoHeader('MWSKZ', e.target.value)} placeholder="세금코드 (MWSKZ)" />
updatePoHeader('LANDS', e.target.value)} placeholder="국가키 (LANDS)" />
updatePoHeader('ZRCV_DT', e.target.value)} placeholder="수령일 (ZRCV_DT)" />
updatePoHeader('ZATTEN_IND', e.target.value)} placeholder="참석지시자 (ZATTEN_IND)" />
updatePoHeader('IHRAN', e.target.value)} placeholder="입찰마감일 (IHRAN)" />
updatePoHeader('TEXT', e.target.value)} placeholder="텍스트 (TEXT)" />
updatePoHeader('LSTEL', e.target.value)} placeholder="배송지점 (LSTEL)" />
updatePoHeader('VSTEL', e.target.value)} placeholder="출하지점 (VSTEL)" />
updatePoHeader('ZDLV_CNTLR', e.target.value)} placeholder="납품담당자 (ZDLV_CNTLR)" />
updatePoHeader('ZDLV_PRICE_NOTE', e.target.value)} placeholder="가격노트 (ZDLV_PRICE_NOTE)" />
updatePoHeader('ZDLV_PRICE_T', e.target.value)} placeholder="가격유형 (ZDLV_PRICE_T)" />
{/* PO 아이템 정보 */}

PO 아이템 정보

{poData.items.map((item, index) => (
아이템 #{index + 1}
{poData.items.length > 1 && ( )}
updatePoItem(index, 'ANFNR', e.target.value)} placeholder="입찰번호 (ANFNR)" />
updatePoItem(index, 'ANFPS', e.target.value)} placeholder="입찰 아이템번호 (ANFPS)" />
updatePoItem(index, 'LIFNR', e.target.value)} placeholder="공급업체 계정 (LIFNR) : 벤더코드" />
updatePoItem(index, 'NETPR', e.target.value)} placeholder="순가격 (NETPR)" />
updatePoItem(index, 'PEINH', e.target.value)} placeholder="가격단위 (PEINH)" />
updatePoItem(index, 'BPRME', e.target.value)} placeholder="주문단위 (BPRME)" />
updatePoItem(index, 'NETWR', e.target.value)} placeholder="순금액 (NETWR)" />
updatePoItem(index, 'BRTWR', e.target.value)} placeholder="총금액 (BRTWR)" />
updatePoItem(index, 'LFDAT', e.target.value)} placeholder="납기일 (LFDAT)" />
updatePoItem(index, 'EBELP', e.target.value)} placeholder="구매오더 품번 (EBELP)" />
updatePoItem(index, 'ZCON_NO_PO', e.target.value)} placeholder="계약번호 (ZCON_NO_PO)" />
))}
{/* 테스트 결과 표시 */} {(testResults['PO 생성 (샘플)'] || testResults['PO 생성 (사용자)']) && (

테스트 결과

{testResults['PO 생성 (샘플)'] && ( )} {testResults['PO 생성 (사용자)'] && ( )}
)}
) } // 테스트 결과 표시 컴포넌트 function TestResultCard({ result, title }: { result: TestResult; title: string }) { return (
{result.success ? ( ) : ( )} {title} {typeof result.statusCode !== 'undefined' && ( HTTP {result.statusCode} )} {result.duration}ms {result.timestamp}

{result.message}

{result.endpoint && (

Endpoint: {result.endpoint}

)} {result.headers && (
응답 헤더 보기
                {Object.entries(result.headers).map(([k, v]) => `${k}: ${v}`).join('\n')}
              
)} {result.requestHeaders && (
요청 헤더 보기
                {Object.entries(result.requestHeaders).map(([k, v]) => `${k}: ${v}`).join('\n')}
              
)} {result.requestXml && (
요청 XML 보기
                {result.requestXml}
              
)} {result.responseData && (
응답 데이터 보기
                {result.responseData}
              
)}
) }